/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "sk6812_spi.h"
#include "py32f002xx_Start_Kit.h"
/* Private define ------------------------------------------------------------*/
#define MAX_EFFECT_MODE 6  // 定义最大灯效模式编号，总共7种效果模式，编号范围0 - 6
#define MAX_SPEED_LEVEL 4  // 定义最大速度等级编号，总共5种速度等级，编号范围0 - 4

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef Spi1Handle;

// 全局变量用于控制灯效模式和速度
volatile uint8_t current_effect_mode = 0;  // 当前效果模式
volatile uint8_t current_speed_level = 2;  // 当前速度等级(默认中等速度)
volatile uint8_t mode_changed = 1;         // 模式改变标志，初始化为1，用于触发灯效重置操作

// 速度等级对应的延时值数组，每个速度等级对应一个延时时间
const uint16_t speed_delays[MAX_SPEED_LEVEL + 1] = {20, 35, 50, 75, 100};

void Error_Handler(void);
void SystemClockConfig(void);
static void SPIConfig(void);
static void ButtonInit(void);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

int main(void)
{
  /* 初始化所有外设，Flash接口，SysTick */
  HAL_Init();

  /* 系统时钟配置 */
  SystemClockConfig();
  SPIConfig();
  /* 初始化LED（用于按键调试指示） */
  BSP_LED_Init(LED3);
  ButtonInit();  // 初始化按键
  HAL_Delay(100); // 添加延时，等待电源稳定

  while (1)
  {
    // 检查模式是否改变，如果改变则重置灯效状态
    if (mode_changed)//只有1和0两个状态，状态机。中断里面标记，主循环里面复位。
    {
      mode_changed = 0;
      effect_reset();  // 重置所有灯效状态
    }
    
    // 根据当前模式执行对应的灯效（非阻塞方式）
    switch (current_effect_mode)
    {
      case 0:
        // 彩虹渐变效果
        rainbow_gradient_update();
        break;
      case 1:
        // 统一颜色渐变效果
        uniform_gradient_update();
        break;
      case 2:
        // 彗星效果
        comet_effect_update();
        break;
      case 3:
        // 红色掉落变绿堆积效果
        red_to_green_stack_update();
        break;
      case 4:
        // Red Wave纯红色波浪效果
        red_wave_update();
        break;
      case 5:
        // Red Green Wave红绿波浪效果
        red_green_wave_update();
        break;
      case 6:
        // Rainbow wave彩虹波浪效果
        rainbow_wave_update();
        break;
      default:
        current_effect_mode = 0;  // 防止越界
        break;
    }
    
    // 短暂延时，避免CPU占用过高
    HAL_Delay(10);
  }
}

static void SPIConfig(void)
{
  /* SPI配置 - 为sk6812/SK6812 */
  Spi1Handle.Instance = SPI1;
  Spi1Handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; /* 24MHz/4 = 6MHz 要求是6.4MHz*/
  Spi1Handle.Init.Direction = SPI_DIRECTION_1LINE;             /* 单向传输，只发送 */
  Spi1Handle.Init.Mode = SPI_MODE_MASTER;                      /* 主机模式 */
  Spi1Handle.Init.DataSize = SPI_DATASIZE_8BIT;                /* 8位数据 */
  Spi1Handle.Init.CLKPolarity = SPI_POLARITY_LOW;              /* 时钟极性低 */
  Spi1Handle.Init.CLKPhase = SPI_PHASE_2EDGE;                  /* 第2个边沿采样 */
  Spi1Handle.Init.NSS = SPI_NSS_SOFT;                          /* 软件NSS */
  Spi1Handle.Init.FirstBit = SPI_FIRSTBIT_MSB;                 /* MSB先发送 */
  if (HAL_SPI_DeInit(&Spi1Handle) != HAL_OK)                   /* SPI反初始化 */
  {
    Error_Handler();
  }
  /* 初始化SPI - HAL_SPI_Init会自动调用HAL_SPI_MspInit配置GPIO */
  if (HAL_SPI_Init(&Spi1Handle) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
 * @brief  按键初始化函数
 * @param  无
 * @retval 无
 */
static void ButtonInit(void)
{
  // 初始化模式减少按键(PB3)配置为外部中断模式
  // 按下时将触发中断服务程序
  BSP_PB_Init(BUTTON_MODE_PREV, BUTTON_MODE_EXTI);

  // 初始化模式增加按键(PB4)
  BSP_PB_Init(BUTTON_MODE_NEXT, BUTTON_MODE_EXTI);

  // 初始化速度调节按键(PB5)
  BSP_PB_Init(BUTTON_SPEED, BUTTON_MODE_EXTI);
}

/**
 * @brief  GPIO外部中断回调函数
 * @param  GPIO_Pin: 触发中断的GPIO引脚
 * @retval 无
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  // 静态变量，用于存储上一次中断发生的时间，实现按键防抖
  static uint32_t last_interrupt_time = 0;
  // 获取当前系统时间（毫秒级）
  uint32_t current_time = HAL_GetTick();

  // 防抖处理：如果当前时间与上次中断时间间隔小于200ms，则忽略本次中断
  // 防止按键机械抖动导致的多次触发
  if (current_time - last_interrupt_time < 200)
  {
    return;
  }
  // 更新上次中断时间为当前时间
  last_interrupt_time = current_time;

  // LED指示按键被按下（调试用）
  BSP_LED_Toggle(LED3);

  switch (GPIO_Pin)
  {
  case GPIO_PIN_0: // 模式减少按键 (PB0)
    if (current_effect_mode > 0) // 如果当前模式大于0，则减1
    {
      current_effect_mode--;
    }
    else
    {
      current_effect_mode = MAX_EFFECT_MODE; // 如果已经是最小模式，则循环到最大模式
    }
    mode_changed = 1; // 标记模式已改变，供主程序处理
    break;

  case GPIO_PIN_1: // 模式增加按键 (PB1)
    if (current_effect_mode < MAX_EFFECT_MODE) // 如果当前模式小于最大模式，则加1
    {
      current_effect_mode++;
    }
    else
    {
      current_effect_mode = 0; // 如果已经是最大模式，则循环到最小模式(0)
    }
    mode_changed = 1; // 标记模式已改变，供主程序处理
    break;

  case GPIO_PIN_6: // 速度调节按键 (PA6)
    if (current_speed_level < MAX_SPEED_LEVEL) // 如果当前速度等级小于最大速度等级，则加1
    {
      current_speed_level++;
    }
    else
    {
      current_speed_level = 0; // 如果已经是最大速度等级，则循环到最小速度等级(0)
    }
    mode_changed = 1; // 标记模式已改变，供主程序处理
    break;

  default:
    // 未处理的引脚中断，不执行任何操作
    break;
  }
}
/**
 * @brief  系统时钟配置函数
 * @param  无
 * @retval 无
 */
void SystemClockConfig(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /* 振荡器配置 */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI; /* 选择振荡器HSE,HSI,LSI */
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;                                                                     /* 开启HSI */
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;                                                                     /* HSI 1分频 */
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_24MHz;                                            /* 配置HSI时钟24MHz */
  RCC_OscInitStruct.HSEState = RCC_HSE_OFF;                                                                    /* 关闭HSE */
  /*RCC_OscInitStruct.HSEFreq = RCC_HSE_16_32MHz;*/
  RCC_OscInitStruct.LSIState = RCC_LSI_OFF; /* 关闭LSI */

  /* 配置振荡器 */
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /* 时钟源配置 */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1; /* 选择配置时钟 HCLK,SYSCLK,PCLK1 */
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;                                         /* 选择HSI作为系统时钟 */
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;                                             /* AHB时钟 1分频 */
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;                                              /* APB时钟 1分频 */
  /* 配置时钟源 */
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
 * @brief  错误执行函数
 * @param  无
 * @retval 无
 */
void Error_Handler(void)
{
  /* 无限循环 */
  while (1)
  {
  }
}

#ifdef USE_FUHAL_ASSERT
  /**
   * @brief  输出产生断言错误的源文件名及行号
   * @param  file：源文件名指针
   * @param  line：发生断言错误的行号
   * @retval 无
   */
  void assert_failed(uint8_t *file, uint32_t line)
  {
    /* 用户可以根据需要添加自己的打印信息,
       例如: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* 无限循环 */
    while (1)
    {
    }
  }
#endif /* USE_FUHAL_ASSERT */

  /************************ (C) COPYRIGHT Puya *****END OF FILE****/
